#include "SiteCoordinate.h"

#include "CellCoordinate.h"
#include "CatanClassContractException.h"

namespace catan
{

// Normalization shorthand (read conversion.txt for more)
// 
// .h-cr:
//     $ =    +0 -> .h-cr
// .h-tr:
//     $ = +v-tr -> .h-cl
// .v-tl:
//     $ = +v-tl -> .v-cr
// .h-cl:
//     $ =    +0 -> .h-cl
// .v-bl:
//     $ = +v-bl -> .v-cr
// .v-br:
//     $ = +v-br -> .v-cl

/*static*/ bool SiteCoordinate::canInit(CoordinateX coordinateX, CoordinateY coordinateY, HorizontalCardinal horizontalCardinal)
{
	if (CellCoordinate::canInit(coordinateX, coordinateY))
	{
		CellCoordinate parentCellCoordinate(coordinateX, coordinateY);
		
		switch (horizontalCardinal.getEnum())
		{
		case HorizontalCardinal::HORIZONTAL_CR:
		case HorizontalCardinal::HORIZONTAL_CL:
			break;
		case HorizontalCardinal::HORIZONTAL_TR:
			if (parentCellCoordinate.canCreateNeighbor(catan::verticalTR))
			{
				parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalTR);
				horizontalCardinal = catan::horizontalCL;
			}
			else
			{
				return false;
			}
			break;
		case HorizontalCardinal::HORIZONTAL_TL:
			if (parentCellCoordinate.canCreateNeighbor(catan::verticalTL))
			{
				parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalTL);
				horizontalCardinal = catan::horizontalCR;
			}
			else
			{
				return false;
			}
			break;
		case HorizontalCardinal::HORIZONTAL_BL:
			if (parentCellCoordinate.canCreateNeighbor(catan::verticalBL))
			{
				parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBL);
				horizontalCardinal = catan::horizontalCR;
			}
			else
			{
				return false;
			}
			break;
		case HorizontalCardinal::HORIZONTAL_BR:
			if (parentCellCoordinate.canCreateNeighbor(catan::verticalBR))
			{
				parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBR);
				horizontalCardinal = catan::horizontalCL;
			}
			else
			{
				return false;
			}
			break;
		default:
			return false;
		}
		
		bool isMapCR = parentCellCoordinate.isOnGameMapEdge(catan::horizontalCR);
		bool isMapTR = parentCellCoordinate.isOnGameMapEdge(catan::horizontalTR);
		bool isMapTL = parentCellCoordinate.isOnGameMapEdge(catan::horizontalTL);
		bool isMapCL = parentCellCoordinate.isOnGameMapEdge(catan::horizontalCL);
		bool isMapBL = parentCellCoordinate.isOnGameMapEdge(catan::horizontalBL);
		bool isMapBR = parentCellCoordinate.isOnGameMapEdge(catan::horizontalBR);
		
		switch (horizontalCardinal.getEnum())
		{
		case HorizontalCardinal::HORIZONTAL_CR:
			return (!isMapCR && !isMapTR && !isMapBR);
		case HorizontalCardinal::HORIZONTAL_CL:
			return (!isMapTL && !isMapCL && !isMapBL);
		default:
			return false;  // Should never happen.
		}
	}
	return false;
}

SiteCoordinate::SiteCoordinate(CoordinateX coordinateX, CoordinateY coordinateY, HorizontalCardinal horizontalCardinal) : BaseCoordinate(coordinateX, coordinateY), horizontalCardinal(horizontalCardinal)
{
	//harborType = NULL;
	if (!SiteCoordinate::canInit(coordinateX, coordinateY, horizontalCardinal))
	{
		throw CatanClassContractException(__FILE__, __LINE__, "SiteCoordinate::canInit(...) with constructor arguments should be true before creating instance.");
	}
	
	CellCoordinate parentCellCoordinate(coordinateX, coordinateY);
	switch (horizontalCardinal.getEnum())
	{
	case HorizontalCardinal::HORIZONTAL_TR:
		parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalTR);
		this->coordinateX = parentCellCoordinate.getCoordinateX();
		this->coordinateY = parentCellCoordinate.getCoordinateY();
		this->horizontalCardinal = catan::horizontalCL;
		break;
	case HorizontalCardinal::HORIZONTAL_TL:
		parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalTL);
		this->coordinateX = parentCellCoordinate.getCoordinateX();
		this->coordinateY = parentCellCoordinate.getCoordinateY();
		this->horizontalCardinal = catan::horizontalCR;
		break;
	case HorizontalCardinal::HORIZONTAL_BL:
		parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBL);
		this->coordinateX = parentCellCoordinate.getCoordinateX();
		this->coordinateY = parentCellCoordinate.getCoordinateY();
		this->horizontalCardinal = catan::horizontalCR;
		break;
	case HorizontalCardinal::HORIZONTAL_BR:
		parentCellCoordinate = parentCellCoordinate.createNeighbor(catan::verticalBR);
		this->coordinateX = parentCellCoordinate.getCoordinateX();
		this->coordinateY = parentCellCoordinate.getCoordinateY();
		this->horizontalCardinal = catan::horizontalCL;
		break;
	default:
		break;
	}
}

HorizontalCardinal SiteCoordinate::getHorizontalCardinal() const
{
	return horizontalCardinal;
}

bool SiteCoordinate::operator==(const SiteCoordinate &other) const
{
	return (coordinateX == other.coordinateX && coordinateY == other.coordinateY && horizontalCardinal == other.horizontalCardinal);
}

bool SiteCoordinate::operator<(const SiteCoordinate &other) const
{
	return (
			(horizontalCardinal < other.horizontalCardinal || (horizontalCardinal == other.horizontalCardinal &&
					(coordinateY < other.coordinateY || (coordinateY == other.coordinateY &&
							(coordinateX < other.coordinateX)
					))
			))
	       );
}

SiteCoordinate& SiteCoordinate::operator=(const SiteCoordinate& other)
{
    if (this != &other)
    {
        coordinateX = other.coordinateX;
        coordinateY = other.coordinateY;
        horizontalCardinal = other.horizontalCardinal;
    }
    return *this;	
}

}
